﻿/*
 * Copyright (c) 2020-2025, Qingdao Digital Intelligent Ship & Ocean Technology Co., Ltd.
 * All rights reserved.
 *
 * This file is part of FastCAE and is distributed under the terms of the
 * BSD 3-Clause License. See the LICENSE file in the project root for details.
 */

#include "FITKShapeFix_FixSmallFace.h"

#include <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <BRepLib.hxx>
#include <BRepTools.hxx>
#include <ElCLib.hxx>
#include <Geom2d_Curve.hxx>
#include <Geom_BezierSurface.hxx>
#include <Geom_BSplineSurface.hxx>
#include <Geom_Curve.hxx>
#include <Geom_ElementarySurface.hxx>
#include <Geom_Line.hxx>
#include <Geom_Surface.hxx>
#include <Geom_TrimmedCurve.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <GeomAdaptor_Surface.hxx>
#include <GeomLib.hxx>
#include <gp_Dir.hxx>
#include <gp_Vec.hxx>
#include <Message_Msg.hxx>
#include <Poly_Polygon3D.hxx>
#include <Precision.hxx>
#include <ShapeAnalysis_Curve.hxx>
#include <ShapeAnalysis_DataMapOfShapeListOfReal.hxx>
#include <ShapeBuild_ReShape.hxx>
#include <ShapeFix_Edge.hxx>
#include <ShapeFix_Face.hxx>
#include <ShapeFix_Shape.hxx>
#include <ShapeFix_Wire.hxx>
#include <Standard_Type.hxx>
#include <TColgp_Array1OfPnt.hxx>
#include <TColgp_Array2OfPnt.hxx>
#include <TColgp_SequenceOfXYZ.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Builder.hxx>
#include <TopoDS_Compound.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Iterator.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Shell.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopoDS_Wire.hxx>
#include <TopTools_Array1OfShape.hxx>
#include <TopTools_DataMapOfShapeListOfShape.hxx>

IMPLEMENT_STANDARD_RTTIEXT(FITKShapeFix_FixSmallFace, ShapeFix_Root)

//#include <GeomLProp_SLProps.hxx>
//#include <TColStd_Array2OfReal.hxx>
//#include <TColStd_Array1OfReal.hxx>
FITKShapeFix_FixSmallFace::FITKShapeFix_FixSmallFace()
{
    myStatus = ShapeExtend::EncodeStatus(ShapeExtend_OK);
    SetPrecision(Precision::Confusion());

}

void FITKShapeFix_FixSmallFace::Init(const TopoDS_Shape& S)
{
    myShape = S;
    if (Context().IsNull())
        SetContext(new ShapeBuild_ReShape);
    myResult = myShape;
    Context()->Apply(myShape);
}

void FITKShapeFix_FixSmallFace::SetPrecision(const Standard_Real preci)
{
    myAnalyzer.SetTolerance(preci);
    ShapeFix_Root::SetPrecision(preci);
}

void FITKShapeFix_FixSmallFace::Perform()
{
    FixSpotFace();
    FixStripFace();
}

void FITKShapeFix_FixSmallFace::Update()
{
    myShape = Context()->Apply(myShape);
    myResult = myShape;
}

TopoDS_Shape FITKShapeFix_FixSmallFace::FixSpotFace()
{

    // gp_Pnt spot;
    // Standard_Real spotol;
    Standard_Boolean done = Standard_False;
    TopAbs_ShapeEnum st = myShape.ShapeType();
    if (st == TopAbs_COMPOUND || st == TopAbs_COMPSOLID || st == TopAbs_SOLID || st == TopAbs_SHELL || st == TopAbs_FACE) {
        for (TopExp_Explorer itf(myShape, TopAbs_FACE); itf.More(); itf.Next()) {
            //smh#8
            TopoDS_Shape tmpFace = Context()->Apply(itf.Current());
            TopoDS_Face F = TopoDS::Face(tmpFace);
            if (F.IsNull()) continue;
            if (myAnalyzer.CheckSpotFace(F, Precision()))
            {
                ReplaceVerticesInCaseOfSpot(F, Precision());
                RemoveFacesInCaseOfSpot(F);
                myStatus = ShapeExtend::EncodeStatus(ShapeExtend_DONE1);
                done = Standard_True;
            }
        }
        myShape = Context()->Apply(myShape);
        Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire;
        if (done)
        {
            if (myShape.IsNull()) return myShape;
            /*ShapeFix_Wire sfw;
            sfw.SetContext(Context());
            sfw.SetPrecision(Precision::Confusion());
            if (myShape.IsNull()) return myShape;
            for (TopExp_Explorer itfw (myShape,TopAbs_FACE); itfw.More(); itfw.Next()) {
              for (TopExp_Explorer itw (myShape,TopAbs_WIRE); itw.More(); itw.Next()) {
                TopoDS_Wire w = TopoDS::Wire(itw.Current());
                sfw.Init(w, TopoDS::Face(itfw.Current()), Precision::Confusion());
                sfw->FixNotchedEdgesMode() = 0;
                if(sfw.Perform())
                Context()->Replace(w, sfw.Wire());
              }
            }*/
            myShape = FixShape();
        }

        //myShape = Context()->Apply(myShape);
        myResult = myShape;
    }
    return myShape;
}

bool FITKShapeFix_FixSmallFace::FixSpotFace(TopoDS_Face face)
{
    // gp_Pnt spot;
// Standard_Real spotol;
    Standard_Boolean done = Standard_False;
    TopAbs_ShapeEnum st = myShape.ShapeType();
    if (st == TopAbs_COMPOUND || st == TopAbs_COMPSOLID || st == TopAbs_SOLID || st == TopAbs_SHELL || st == TopAbs_FACE) {
        for (TopExp_Explorer itf(myShape, TopAbs_FACE); itf.More(); itf.Next()) {
            //smh#8
            TopoDS_Shape tmpFace = Context()->Apply(itf.Current());
            TopoDS_Face F = TopoDS::Face(tmpFace);
            if (F.IsNull()) continue;

            if (!face.IsSame(F))
            {
                continue;
            }

            if (myAnalyzer.CheckSpotFace(F, Precision()))
            {
                ReplaceVerticesInCaseOfSpot(F, Precision());
                RemoveFacesInCaseOfSpot(F);
                myStatus = ShapeExtend::EncodeStatus(ShapeExtend_DONE1);
                done = Standard_True;
            }

            break;
        }
        //myShape = Context()->Apply(myShape);
        //Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire;
        //if (done)
        //{
        //    if (myShape.IsNull()) return done;
        //    /*ShapeFix_Wire sfw;
        //    sfw.SetContext(Context());
        //    sfw.SetPrecision(Precision::Confusion());
        //    if (myShape.IsNull()) return myShape;
        //    for (TopExp_Explorer itfw (myShape,TopAbs_FACE); itfw.More(); itfw.Next()) {
        //      for (TopExp_Explorer itw (myShape,TopAbs_WIRE); itw.More(); itw.Next()) {
        //        TopoDS_Wire w = TopoDS::Wire(itw.Current());
        //        sfw.Init(w, TopoDS::Face(itfw.Current()), Precision::Confusion());
        //        sfw->FixNotchedEdgesMode() = 0;
        //        if(sfw.Perform())
        //        Context()->Replace(w, sfw.Wire());
        //      }
        //    }*/
        //    myShape = FixShape();
        //}

        //myResult = myShape;
    }

    return done;
}

Standard_Boolean FITKShapeFix_FixSmallFace::ReplaceVerticesInCaseOfSpot(TopoDS_Face& F, const Standard_Real /*tol*/) const
{

    TColgp_SequenceOfXYZ thePositions;
    gp_XYZ thePosition;
    BRep_Builder theBuilder;
    Standard_Real theMaxDev;
    Standard_Real theMaxTol = 0.0;
    thePositions.Clear();
    gp_Pnt thePoint;
    //smh#8
    TopoDS_Shape tmpFace = Context()->Apply(F);
    F = TopoDS::Face(tmpFace);
    // gka Mar2000 Protection against faces without wires
    // but they occur due to bugs in the algorithm itself, it needs to be fixed
    Standard_Boolean isWir = Standard_False;
    for (TopoDS_Iterator itw(F, Standard_False); itw.More(); itw.Next()) {
        if (itw.Value().ShapeType() != TopAbs_WIRE)
            continue;
        TopoDS_Wire w1 = TopoDS::Wire(itw.Value());
        if (!w1.IsNull()) { isWir = Standard_True; break; }
    }
    if (!isWir) return Standard_True;
    //Accumulating positions and maximal vertex tolerance
    for (TopExp_Explorer iter_vertex(F, TopAbs_VERTEX); iter_vertex.More(); iter_vertex.Next()) {
        TopoDS_Vertex V = TopoDS::Vertex(iter_vertex.Current());
        thePoint = BRep_Tool::Pnt(V);
        if (theMaxTol <= (BRep_Tool::Tolerance(V))) theMaxTol = BRep_Tool::Tolerance(V);
        thePositions.Append(thePoint.XYZ());
    }
    //Calculate common vertex position
    thePosition = gp_XYZ(0., 0., 0.);
    Standard_Integer theNbPos = thePositions.Length();
    Standard_Integer i; // svv Jan11 2000 : porting on DEC
    for (i = 1; i <= theNbPos; i++) thePosition += thePositions.Value(i);
    if (theNbPos > 1) thePosition /= theNbPos;

    // Calculate maximal deviation
    theMaxDev = 0.;
    for (i = 1; i <= theNbPos; i++) {
        Standard_Real theDeviation = (thePosition - thePositions.Value(i)).Modulus();
        if (theDeviation > theMaxDev) theMaxDev = theDeviation;
    }
    theMaxDev *= 1.00001;

    //Cretate new vertex with mean point
    TopoDS_Vertex theSharedVertex;
    theBuilder.MakeVertex(theSharedVertex);
    theBuilder.UpdateVertex(theSharedVertex, gp_Pnt(thePosition), theMaxDev + theMaxTol / 2);
    //Use external tolerance
  //   if (tol!=-1.0) theBuilder.UpdateVertex( theSharedVertex, tol);
    //Replacing all vertices in the face by new one
    TopoDS_Vertex theNewVertex;
    for (TopExp_Explorer iter_vert(F, TopAbs_VERTEX); iter_vert.More(); iter_vert.Next()) {
        TopoDS_Vertex V = TopoDS::Vertex(iter_vert.Current());
        if (V.Orientation() == TopAbs_FORWARD)
            //smh#8
        {
            TopoDS_Shape tmpVertexFwd = theSharedVertex.Oriented(TopAbs_FORWARD);
            theNewVertex = TopoDS::Vertex(tmpVertexFwd);
        }
        else
            //smh#8
        {
            TopoDS_Shape tmpVertexRev = theSharedVertex.Oriented(TopAbs_REVERSED);
            theNewVertex = TopoDS::Vertex(tmpVertexRev);
        }
        Context()->Replace(V, theNewVertex);
    }
    return Standard_True;
}

Standard_Boolean FITKShapeFix_FixSmallFace::RemoveFacesInCaseOfSpot(const TopoDS_Face& F) const
{
    for (TopExp_Explorer iter_vert(F, TopAbs_EDGE); iter_vert.More(); iter_vert.Next()) {
        TopoDS_Edge Ed = TopoDS::Edge(iter_vert.Current());
        Context()->Remove(Ed);
    }
    Context()->Remove(F);
    SendWarning(F, Message_Msg("FixAdvFace.FixSpotFace.MSG0"));
    return Standard_True;


}

TopoDS_Shape FITKShapeFix_FixSmallFace::FixStripFace(const Standard_Boolean wasdone)
{
    if (myShape.IsNull()) return myShape;
    TopAbs_ShapeEnum st = myShape.ShapeType();
    // BRep_Builder theBuilder;
    Standard_Boolean done = wasdone;
    if (st == TopAbs_COMPOUND || st == TopAbs_COMPSOLID || st == TopAbs_SOLID || st == TopAbs_SHELL || st == TopAbs_FACE) {
        for (TopExp_Explorer itf(myShape, TopAbs_FACE); itf.More(); itf.Next()) {
            TopoDS_Face F = TopoDS::Face(itf.Current());
            //smh#8
            TopoDS_Shape tmpFace = Context()->Apply(F);
            F = TopoDS::Face(tmpFace);
            if (F.IsNull()) continue;
            // Standard_Real dmax = 1;
            TopoDS_Edge E1, E2;
            if (myAnalyzer.CheckStripFace(F, E1, E2, Precision()))
            {
                if (ReplaceInCaseOfStrip(F, E1, E2, Precision()))
                    RemoveFacesInCaseOfStrip(F);
                myStatus = ShapeExtend::EncodeStatus(ShapeExtend_DONE2);
                done = Standard_True;
            }
        }
        myShape = Context()->Apply(myShape);
        //Particular case of empty shell
        if (!myShape.IsNull())
        {
            for (TopExp_Explorer exp_s(myShape, TopAbs_SHELL); exp_s.More(); exp_s.Next()) {
                TopoDS_Shell Sh = TopoDS::Shell(exp_s.Current());
                TopExp_Explorer ex_sh(Sh, TopAbs_FACE);
                if (!ex_sh.More()) {
                    Context()->Remove(Sh);
                    // 				std::cout << "Empty shell was removed" << std::endl; 
                }
            }
            myShape = Context()->Apply(myShape);
            //Fixing of missing pcurves on new edges, if thay were inserted
            if (done)
            {
                if (myShape.IsNull()) return myShape;
                TopoDS_Shape theResult;
                myShape = FixShape();
                //myShape = Context()->Apply(myShape);
                myResult = myShape;
            }

        }
    }
    return myShape;

}

bool FITKShapeFix_FixSmallFace::FixStripFace(TopoDS_Face face)
{
    Standard_Boolean done = Standard_False;

    if (myShape.IsNull()) return Standard_False;
    TopAbs_ShapeEnum st = myShape.ShapeType();
    // BRep_Builder theBuilder;
    
    if (st == TopAbs_COMPOUND || st == TopAbs_COMPSOLID || st == TopAbs_SOLID || st == TopAbs_SHELL || st == TopAbs_FACE) {
        for (TopExp_Explorer itf(myShape, TopAbs_FACE); itf.More(); itf.Next()) {
            TopoDS_Face F = TopoDS::Face(itf.Current());
            //smh#8
            TopoDS_Shape tmpFace = Context()->Apply(F);
            F = TopoDS::Face(tmpFace);
            if (F.IsNull()) continue;

            if (!face.IsSame(F))
            {
                continue;
            }

            // Standard_Real dmax = 1;
            TopoDS_Edge E1, E2;
            if (myAnalyzer.CheckStripFace(F, E1, E2, Precision()))
            {
                if (ReplaceInCaseOfStrip(F, E1, E2, Precision()))
                    RemoveFacesInCaseOfStrip(F);
                myStatus = ShapeExtend::EncodeStatus(ShapeExtend_DONE2);
                done = Standard_True;
            }

            break;
        }
        //myShape = Context()->Apply(myShape);
        ////Particular case of empty shell
        //if (!myShape.IsNull())
        //{
        //    for (TopExp_Explorer exp_s(myShape, TopAbs_SHELL); exp_s.More(); exp_s.Next()) {
        //        TopoDS_Shell Sh = TopoDS::Shell(exp_s.Current());
        //        TopExp_Explorer ex_sh(Sh, TopAbs_FACE);
        //        if (!ex_sh.More()) {
        //            Context()->Remove(Sh);
        //            // 				std::cout << "Empty shell was removed" << std::endl; 
        //        }
        //    }
        //    myShape = Context()->Apply(myShape);
        //    //Fixing of missing pcurves on new edges, if thay were inserted
        //    if (done)
        //    {
        //        if (myShape.IsNull()) return done;
        //        TopoDS_Shape theResult;
        //        myShape = FixShape();
        //        //myShape = Context()->Apply(myShape);
        //        myResult = myShape;
        //    }

        //}
    }
    return done;
}

Standard_Boolean FITKShapeFix_FixSmallFace::ReplaceInCaseOfStrip(TopoDS_Face& F, TopoDS_Edge& E1, TopoDS_Edge& E2, const Standard_Real tol) const
{
    if (E1.IsNull() || E2.IsNull()) return Standard_False;
    TopoDS_Edge theSharedEdge;
    TopoDS_Face F1, F2;
    //smh#8
    TopoDS_Shape tmpFace = Context()->Apply(F);
    F = TopoDS::Face(tmpFace);
    for (TopExp_Explorer expf(myShape, TopAbs_FACE); expf.More(); expf.Next()) {
        //smh#8
        TopoDS_Shape tmpShape = Context()->Apply(expf.Current());
        TopoDS_Face tempF = TopoDS::Face(tmpShape);
        if (tempF.IsNull() || tempF.IsSame(F)) continue;
        for (TopExp_Explorer expe(tempF, TopAbs_EDGE); expe.More(); expe.Next()) {
            TopoDS_Edge tempE = TopoDS::Edge(expe.Current());
            if (tempE.IsSame(E1)) F1 = tempF;
            if (tempE.IsSame(E2)) F2 = tempF;
            if (!F1.IsNull()) break; // && !F2.IsNull()) break;
        }
    }

    //Compute shared edge for this face
    if (F1.IsNull() && F2.IsNull()) return Standard_True;
    TopoDS_Edge E1tmp = E1;
    TopoDS_Edge E2tmp = E2;
    if (F1.IsNull()) {
        E1tmp = E2;
        E2tmp = E1;
        F1 = F2;
    }
    theSharedEdge = ComputeSharedEdgeForStripFace(F, E1tmp, E2tmp, F1, tol);
    //Replace two long edges by new one
    if (theSharedEdge.IsNull()) return Standard_False;
    if (E1.Orientation() == TopAbs_REVERSED) {
        Context()->Replace(E1tmp, theSharedEdge.Oriented(TopAbs_REVERSED));
        if (F.Orientation() == F1.Orientation())
            Context()->Replace(E2tmp, theSharedEdge);
        else
            Context()->Replace(E2tmp, theSharedEdge.Oriented(TopAbs_REVERSED));
    }
    else
    {
        Context()->Replace(E1tmp, theSharedEdge);
        if (F.Orientation() == F1.Orientation())
            Context()->Replace(E2tmp, theSharedEdge.Oriented(TopAbs_REVERSED));
        else
            Context()->Replace(E2tmp, theSharedEdge);
    }

    //Remove short edges
    for (TopExp_Explorer exp_e(F, TopAbs_EDGE); exp_e.More(); exp_e.Next()) {
        TopoDS_Edge shortedge = TopoDS::Edge(exp_e.Current());
        if (!shortedge.IsSame(E1tmp) && !shortedge.IsSame(E2tmp)) Context()->Remove(shortedge);
    }

    return Standard_True;
}

Standard_Boolean FITKShapeFix_FixSmallFace::RemoveFacesInCaseOfStrip(const TopoDS_Face& F) const
{
    Context()->Remove(F);
    SendWarning(F, Message_Msg("FixAdvFace.FixStripFace.MSG0"));
    return Standard_True;
}

TopoDS_Edge FITKShapeFix_FixSmallFace::ComputeSharedEdgeForStripFace(const TopoDS_Face& /*F*/, const TopoDS_Edge& E1, const TopoDS_Edge& E2, const TopoDS_Face& F1, const Standard_Real tol) const
{

    BRep_Builder theBuilder;
    //Compute deviation between two vertices and create new vertices
    TopoDS_Edge theNewEdge;
    TopoDS_Vertex V1, V2, V3, V4;
    TopExp::Vertices(E1, V1, V2);
    TopExp::Vertices(E2, V3, V4);
    gp_Pnt p1, p2;
    Standard_Real dev;
    p1 = BRep_Tool::Pnt(V1);
    p2 = BRep_Tool::Pnt(V3);
    dev = p1.Distance(p2);
    TopoDS_Vertex theFirstVer;
    TopoDS_Vertex theSecondVer;
    theBuilder.MakeVertex(theFirstVer);
    theBuilder.MakeVertex(theSecondVer);
    gp_XYZ thePosition;
    TopoDS_Shape temp;

    if ((dev <= BRep_Tool::Tolerance(V1)) || (dev <= BRep_Tool::Tolerance(V3)) || (dev <= tol)) {
        if (V1.IsSame(V3))
            // #ifdef AIX  CKY : applies to all platforms
            theFirstVer = V1;
        //	theFirstVer = TopoDS::Vertex(V1); 

        else {
            dev = (dev / 2)*1.0001;
            thePosition = (p1.XYZ() + p2.XYZ()) / 2;
            theBuilder.UpdateVertex(theFirstVer, gp_Pnt(thePosition), dev);
            //if(Context()->Status(V1, temp) != 0) theFirstVer = TopoDS::Vertex (temp); //If this vertex already recorded in map
            //else                                                                       //take recorded vertex 
            //  if(theRepVert->Status(V3, temp) != 0) theFirstVer = TopoDS::Vertex (temp);
            if (V1.Orientation() == TopAbs_FORWARD) Context()->Replace(V1, theFirstVer.Oriented(TopAbs_FORWARD));
            else Context()->Replace(V1, theFirstVer.Oriented(TopAbs_REVERSED));
            if (V3.Orientation() == TopAbs_FORWARD) Context()->Replace(V3, theFirstVer.Oriented(TopAbs_FORWARD));
            else Context()->Replace(V3, theFirstVer.Oriented(TopAbs_REVERSED));

        }
        if (V1.IsSame(V2) || V3.IsSame(V4))
            theSecondVer = theFirstVer;
        else {
            if (!V2.IsSame(V4)) {
                // #ifdef AIX  CKY : applies to all platforms

                p1 = BRep_Tool::Pnt(V2);
                p2 = BRep_Tool::Pnt(V4);
                dev = p1.Distance(p2);
                thePosition = (p1.XYZ() + p2.XYZ()) / 2;
                theBuilder.UpdateVertex(theSecondVer, gp_Pnt(thePosition), dev);
                //if(theRepVert->Status(V2, temp) != 0) theSecondVer = TopoDS::Vertex (temp); //If this vertex already recorded in map
                //else 
                //  if(theRepVert->Status(V4, temp) != 0) theSecondVer = TopoDS::Vertex (temp);
            }
            else theSecondVer = V2;

        }
        if (!V2.IsSame(theSecondVer)) {
            if (V2.Orientation() == TopAbs_FORWARD) Context()->Replace(V2, theSecondVer.Oriented(TopAbs_FORWARD));
            else Context()->Replace(V2, theSecondVer.Oriented(TopAbs_REVERSED));
            if (V4.Orientation() == TopAbs_FORWARD) Context()->Replace(V4, theSecondVer.Oriented(TopAbs_FORWARD));
            else Context()->Replace(V4, theSecondVer.Oriented(TopAbs_REVERSED));
        }
    }
    else {
        p2 = BRep_Tool::Pnt(V4);
        dev = p1.Distance(p2);
        if ((dev <= BRep_Tool::Tolerance(V1)) || (dev <= BRep_Tool::Tolerance(V4)) || (dev <= tol)) {
            if (V1.IsSame(V4))
                // #ifdef AIX  CKY : applies to all platforms
                theFirstVer = V1;
            //	    theFirstVer = TopoDS::Vertex(V1);

            else {
                dev = (dev / 2)*1.0001;
                thePosition = (p1.XYZ() + p2.XYZ()) / 2;
                theBuilder.UpdateVertex(theFirstVer, gp_Pnt(thePosition), dev);
                //    if(theRepVert->Status(V1, temp) != 0) theFirstVer = TopoDS::Vertex (temp); //If this vertex already recorded in map
                  //  else 
                  //    if(theRepVert->Status(V4, temp) != 0) theFirstVer = TopoDS::Vertex (temp);
                if (V1.Orientation() == TopAbs_FORWARD) Context()->Replace(V1, theFirstVer.Oriented(TopAbs_FORWARD));
                else Context()->Replace(V1, theFirstVer.Oriented(TopAbs_REVERSED));
                if (V4.Orientation() == TopAbs_FORWARD) Context()->Replace(V4, theFirstVer.Oriented(TopAbs_FORWARD));
                else Context()->Replace(V4, theFirstVer.Oriented(TopAbs_REVERSED));
            }
            if (V1.IsSame(V2) || V3.IsSame(V4))
                theSecondVer = theFirstVer;
            else {

                if (!V2.IsSame(V3)) {
                    p1 = BRep_Tool::Pnt(V2);
                    p2 = BRep_Tool::Pnt(V3);
                    dev = p1.Distance(p2);
                    thePosition = (p1.XYZ() + p2.XYZ()) / 2;
                    theBuilder.UpdateVertex(theSecondVer, gp_Pnt(thePosition), dev);
                }
                else theSecondVer = V2;
            }
            //  if(theRepVert->Status(V2, temp) != 0) theSecondVer = TopoDS::Vertex (temp); //If this vertex already recorded in map
            // else 
            //  if(theRepVert->Status(V3, temp) != 0) theSecondVer = TopoDS::Vertex (temp);
            if (!V2.IsSame(theSecondVer)) {
                if (V2.Orientation() == TopAbs_FORWARD) Context()->Replace(V2, theSecondVer.Oriented(TopAbs_FORWARD));
                else Context()->Replace(V2, theSecondVer.Oriented(TopAbs_REVERSED));
                if (V3.Orientation() == TopAbs_FORWARD) Context()->Replace(V3, theSecondVer.Oriented(TopAbs_FORWARD));
                else Context()->Replace(V3, theSecondVer.Oriented(TopAbs_REVERSED));
            }

        }
        else {
#ifdef OCCT_DEBUG
            std::cout << "The face is not strip face" << std::endl;
#endif
            return theNewEdge;
        }
    }
    if (theFirstVer.IsNull() || theSecondVer.IsNull()) return theNewEdge;
    //Cretate new edge 
    theBuilder.MakeEdge(theNewEdge);
    Standard_Real f, l, fp1, lp1/*, fp2, lp2*/;
    TopLoc_Location loc;
    Handle(Geom_Curve) the3dcurve;
    the3dcurve = BRep_Tool::Curve(E1, f, l);
    Handle(Geom2d_Curve) the2dcurve1, the2dcurve2, thenew1, thenew2;
    if (!F1.IsNull())
    {
        the2dcurve1 = BRep_Tool::CurveOnSurface(E1, F1, fp1, lp1);
        if (!the2dcurve1.IsNull() && fp1 != f && lp1 != l) GeomLib::SameRange(Precision::Confusion(), the2dcurve1, fp1, lp1, f, l, thenew1);
    }

    /* if (!F2.IsNull())
       {
         the2dcurve2 = BRep_Tool::CurveOnSurface(E2, F2, fp2, lp2);
         if(!the2dcurve2.IsNull()) GeomLib::SameRange(Precision::Confusion(), the2dcurve2, fp2, lp2, f, l, thenew2);
       }*/

    Standard_Real maxdev;
    if ((BRep_Tool::Tolerance(theFirstVer)) <= (BRep_Tool::Tolerance(theSecondVer)))
        maxdev = (BRep_Tool::Tolerance(theSecondVer));
    else  maxdev = (BRep_Tool::Tolerance(theFirstVer));
    theBuilder.UpdateVertex(theFirstVer, maxdev);
    theBuilder.UpdateVertex(theSecondVer, maxdev);
    //Standard_Boolean IsFree = Standard_True;
    theBuilder.SameParameter(theNewEdge, Standard_False);
    the3dcurve = BRep_Tool::Curve(E1, f, l);
    theBuilder.UpdateEdge(theNewEdge, the3dcurve, maxdev);
    theBuilder.Range(theNewEdge, f, l);
    if (!F1.IsNull() && !thenew1.IsNull())
    {
        theBuilder.UpdateEdge(theNewEdge, thenew1, F1, maxdev);
        //IsFree = Standard_False;
    }
    /*if (!F2.IsNull() && !thenew2.IsNull())
      {
        theBuilder.UpdateEdge(theNewEdge, thenew2, F2, maxdev);
        IsFree = Standard_False;
      }*/
    theBuilder.Add(theNewEdge, theFirstVer.Oriented(TopAbs_FORWARD));
    theBuilder.Add(theNewEdge, theSecondVer.Oriented(TopAbs_REVERSED));
    //Call fixsameparameter for computing distance between 3d and pcurves, if edge is not free
  //   if (!IsFree)
  //     {
  //       ShapeFix_Edge sfe;
  //       if (!F1.IsNull() && !thenew1.IsNull()) sfe.FixReversed2d(theNewEdge, F1);
  //       if (!F2.IsNull() && !thenew2.IsNull()) sfe.FixReversed2d(theNewEdge, F2);
  //       sfe.FixSameParameter(theNewEdge, maxdev);
  //     }
    return theNewEdge;


}

TopoDS_Shape FITKShapeFix_FixSmallFace::FixSplitFace(const TopoDS_Shape& /*S*/)
{
    if (myShape.IsNull()) return myShape;
    TopAbs_ShapeEnum st = myShape.ShapeType();
    Standard_Boolean done = Standard_False;
    TopoDS_Compound theSplittedFaces;
    BRep_Builder theBuilder;
    if (st == TopAbs_COMPOUND || st == TopAbs_COMPSOLID ||
        st == TopAbs_SOLID || st == TopAbs_SHELL || st == TopAbs_FACE) {
        for (TopExp_Explorer itf(myShape, TopAbs_FACE); itf.More(); itf.Next()) {
            TopoDS_Face F = TopoDS::Face(itf.Current());
            TopoDS_Compound CompSplittedFaces;
            theBuilder.MakeCompound(CompSplittedFaces);
            if (SplitOneFace(F, CompSplittedFaces)) {
                done = Standard_True;
                Context()->Replace(F, CompSplittedFaces);
            }
        }
    }
    if (done) myStatus = ShapeExtend::EncodeStatus(ShapeExtend_DONE3);
    myShape = Context()->Apply(myShape);
    myResult = myShape;
    return myShape;
}

Standard_Boolean FITKShapeFix_FixSmallFace::SplitOneFace(TopoDS_Face& F, TopoDS_Compound& theSplittedFaces)
{
    TopTools_DataMapOfShapeListOfShape MapEdges;
    ShapeAnalysis_DataMapOfShapeListOfReal MapParam;
    TopoDS_Compound theAllVert;
    BRep_Builder theBuilder;
    theBuilder.MakeCompound(theAllVert);
    //smh#8
    TopoDS_Shape tmpShape = Context()->Apply(F);
    F = TopoDS::Face(tmpShape);
    if (myAnalyzer.CheckSplittingVertices(F, MapEdges, MapParam, theAllVert) != 0)
    {
        TopoDS_Wire tempwire;
        //Take information about splitting vertices
        if (theAllVert.IsNull()) return Standard_False;
        //Standard_Integer i;
        TopoDS_Vertex V;
        TopExp_Explorer itc(theAllVert, TopAbs_VERTEX); V = TopoDS::Vertex(itc.Current());
        if (V.IsNull()) return Standard_False;
        gp_Pnt proj;
        gp_Pnt vp = BRep_Tool::Pnt(V);
        TopoDS_Vertex theNewVertex;
        TopoDS_Edge E;
        TopoDS_Edge theFirstEdge, theSecondEdge;

        {
            //If one vertex presents do splitting by two faces
            ShapeAnalysis_Curve SAC;
            for (TopExp_Explorer ite(F, TopAbs_EDGE); ite.More(); ite.Next()) {
                E = TopoDS::Edge(ite.Current());
                TopoDS_Vertex V1, V2;
                TopExp::Vertices(E, V1, V2);
                Standard_Real cf, cl;
                Handle(Geom_Curve) C3D = BRep_Tool::Curve(E, cf, cl);
                if (C3D.IsNull()) continue;
                if (V.IsSame(V1) || V.IsSame(V2)) continue;
                Standard_Real vt = BRep_Tool::Tolerance(V);
                Standard_Real param;
                Standard_Real dist = SAC.Project(C3D, vp, vt*10., proj, param, cf, cl);
                if (dist == 0) continue; //Projection on same curve but on other edge ?
                if (dist <= vt)
                {
                    theBuilder.MakeVertex(theNewVertex);
                    theBuilder.UpdateVertex(theNewVertex, proj, Precision::Confusion());
                    theBuilder.MakeEdge(theFirstEdge);
                    theBuilder.MakeEdge(theSecondEdge);
                    Standard_Real f, l;
                    Handle(Geom_Curve) the3dcurve = BRep_Tool::Curve(E, f, l);
                    theBuilder.UpdateEdge(theFirstEdge, the3dcurve, Precision::Confusion());
                    theBuilder.UpdateEdge(theSecondEdge, the3dcurve, Precision::Confusion());
                    if (V1.Orientation() == TopAbs_FORWARD)
                    {
                        theBuilder.Add(theFirstEdge, V1);
                        theBuilder.Add(theFirstEdge, theNewVertex.Oriented(TopAbs_REVERSED));
                        theBuilder.Add(theSecondEdge, theNewVertex.Oriented(TopAbs_FORWARD));
                        theBuilder.Add(theSecondEdge, V2);
                    }
                    else {
                        theBuilder.Add(theFirstEdge, V2);
                        theBuilder.Add(theFirstEdge, theNewVertex.Oriented(TopAbs_REVERSED));
                        theBuilder.Add(theSecondEdge, theNewVertex.Oriented(TopAbs_FORWARD));
                        theBuilder.Add(theSecondEdge, V1);
                    }
                    theBuilder.Range(theFirstEdge, cf, param);
                    theBuilder.Range(theSecondEdge, param, cl);
                    //Replace old edge by two new edges
                    TopoDS_Wire twoedges;
                    theBuilder.MakeWire(twoedges);
                    if (E.Orientation() == TopAbs_FORWARD)
                    {
                        theBuilder.Add(twoedges, theFirstEdge.Oriented(TopAbs_FORWARD));
                        theBuilder.Add(twoedges, theSecondEdge.Oriented(TopAbs_FORWARD));
                    }
                    else
                    {
                        theBuilder.Add(twoedges, theFirstEdge.Oriented(TopAbs_REVERSED));
                        theBuilder.Add(twoedges, theSecondEdge.Oriented(TopAbs_REVERSED));
                    }
                    Context()->Replace(E, twoedges);
                    break;
                }
            }
            if (theNewVertex.IsNull()) return Standard_False;
            //Create split edge
            TopoDS_Edge theSplitEdge;
            gp_Lin lin(vp, gp_Dir(gp_Vec(vp, proj)));
            Standard_Real firstparam = ElCLib::Parameter(lin, vp);
            Standard_Real lastparam = ElCLib::Parameter(lin, proj);
            Handle(Geom_Line) L = new Geom_Line(vp, gp_Vec(vp, proj));
            Handle(Geom_Curve) the3dc = L;
            theBuilder.MakeEdge(theSplitEdge, the3dc, Precision::Confusion());
            theBuilder.Add(theSplitEdge, V.Oriented(TopAbs_FORWARD));
            theBuilder.Add(theSplitEdge, theNewVertex.Oriented(TopAbs_REVERSED));
            theBuilder.Range(theSplitEdge, firstparam, lastparam);
            //Add pcurve in new edge
            Handle(ShapeFix_Edge) sfe = new ShapeFix_Edge;
            sfe->FixAddPCurve(theSplitEdge, F, Standard_False);
            //Reorder the wire 
            TopoDS_Wire wireonface;
            //Inher loop is not support yet !!!
            TopExp_Explorer itw(F, TopAbs_WIRE);
            wireonface = TopoDS::Wire(itw.Current());
            itw.Next();
            if (itw.More()) return Standard_False; //if face contains more than one wire  
            Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire;
            sfw->Init(wireonface, F, Precision::Confusion());
            sfw->FixReorder();
            wireonface = sfw->Wire();

            //Create two new wires
            TopoDS_Wire w1, w2;
            theBuilder.MakeWire(w1);
            theBuilder.MakeWire(w2);
            theBuilder.MakeWire(tempwire);
            for (TopExp_Explorer itnew(wireonface, TopAbs_EDGE); itnew.More(); itnew.Next())
            {
                TopoDS_Edge ce = TopoDS::Edge(itnew.Current());
                if (ce.IsSame(E))
                {
                    theBuilder.Remove(wireonface, ce);
                    theBuilder.Add(wireonface, theFirstEdge.Oriented(TopAbs_FORWARD));
                    theBuilder.Add(wireonface, theSecondEdge.Oriented(TopAbs_FORWARD));
                }
            }
            sfw->Init(wireonface, F, Precision::Confusion());
            sfw->FixReorder();
            wireonface = sfw->Wire();

            for (TopExp_Explorer itere(wireonface, TopAbs_EDGE); itere.More(); itere.Next())
            {
                TopoDS_Edge ce = TopoDS::Edge(itere.Current());
                TopoDS_Vertex thecontrol;
                if (ce.Orientation() == TopAbs_FORWARD) thecontrol = TopExp::LastVertex(ce);
                else thecontrol = TopExp::FirstVertex(ce);
                theBuilder.Add(w1, ce);
                if (thecontrol.IsSame(V))
                {
                    theBuilder.Add(w1, theSplitEdge.Oriented(TopAbs_FORWARD));
                    TopoDS_Wire wtemp = w1;
                    w1 = w2;
                    w2 = wtemp;
                }
                if (thecontrol.IsSame(theNewVertex))
                {
                    theBuilder.Add(w1, theSplitEdge.Oriented(TopAbs_REVERSED));
                    TopoDS_Wire wtemp = w1;
                    w1 = w2;
                    w2 = wtemp;
                }
            }
            if (w1.IsNull() || w2.IsNull()) return Standard_False;
            //Create two new faces and replace old one
            TopoDS_Face F1;
            TopoDS_Face F2;
            theBuilder.MakeFace(F1, BRep_Tool::Surface(F), Precision::Confusion());
            theBuilder.MakeFace(F2, BRep_Tool::Surface(F), Precision::Confusion());
            theBuilder.Add(F1, w1);
            theBuilder.Add(F2, w2);
            TopoDS_Compound tf;
            theBuilder.MakeCompound(tf);
            theBuilder.Add(tf, F1);
            theBuilder.Add(tf, F2);
            //Call recursive spliteoneface() for each face     
            if (!SplitOneFace(F1, theSplittedFaces)) theBuilder.Add(theSplittedFaces, F1);
            if (!SplitOneFace(F2, theSplittedFaces)) theBuilder.Add(theSplittedFaces, F2);
        }
        return Standard_True;
    }
    return Standard_False;
}

TopoDS_Face FITKShapeFix_FixSmallFace::FixFace(const TopoDS_Face& F)
{
    //smh#8
    TopoDS_Shape emptyCopied = F.EmptyCopied();
    TopoDS_Face theFixedFace = TopoDS::Face(emptyCopied);
    // BRep_Builder theBuilder;

    // Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire;
    // sfw->SetContext(Context());
    // for (TopExp_Explorer exp_w (F,TopAbs_WIRE); exp_w.More(); exp_w.Next()) {
    //   TopoDS_Wire theCurWire = TopoDS::Wire (exp_w.Current());

    //   sfw->Init(theCurWire,  F, Precision::Confusion());
    //   if(sfw->NbEdges() == 0) continue;
    //   sfw->FixNotchedEdgesMode() = 0;
    //   sfw->Perform();
    //   theCurWire = sfw->Wire();
    //   theBuilder.Add(theFixedFace, theCurWire);
    // }
    Handle(ShapeFix_Face) sff = new ShapeFix_Face;
    sff->SetContext(Context());
    sff->Init(F);
    sff->Perform();
    //sff->Init(theFixedFace);
    //sff->FixOrientation();
    theFixedFace = sff->Face();
    return theFixedFace;
}

TopoDS_Shape FITKShapeFix_FixSmallFace::FixShape()
{
    TopoDS_Shape FixSh;
    if (myShape.IsNull()) return FixSh;
    /*ShapeFix_Shape sfs;
    sfs.SetContext(Context());

    sfs.SetPrecision(Precision::Confusion());
    sfs.Init(myShape);
    sfs.Perform();
    FixSh = sfs.Shape();*/
    for (TopExp_Explorer expf(myShape, TopAbs_FACE); expf.More(); expf.Next()) {
        TopoDS_Face F = TopoDS::Face(expf.Current());
        //smh#8
        TopoDS_Shape tmpFace = Context()->Apply(F);
        F = TopoDS::Face(tmpFace);
        TopoDS_Face newF = FixFace(F);
        Context()->Replace(F, newF);
    }
    FixSh = Context()->Apply(myShape);
    return FixSh;

}
TopoDS_Shape FITKShapeFix_FixSmallFace::Shape()
{
    return myShape;
}

Standard_Boolean FITKShapeFix_FixSmallFace::FixPinFace(TopoDS_Face& /*F*/)
{
    return Standard_True;
}
